package xyz.xtt.asset.script;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import xyz.xtt.asset.api.enums.SecondEnum;
import xyz.xtt.asset.constants.AssetCardDestoryStatenum;
import xyz.xtt.asset.entity.TblAsset;
import xyz.xtt.asset.entity.TblAssetCard;
import xyz.xtt.asset.entity.TblAssetExt;
import xyz.xtt.asset.entity.TblAssetNo;
import xyz.xtt.asset.service.ITblAssetCardService;
import xyz.xtt.asset.service.ITblAssetExtService;
import xyz.xtt.asset.service.ITblAssetNoService;
import xyz.xtt.asset.service.ITblAssetService;
import xyz.xtt.common.response.ApiResult;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author dale
 * @date 2025/3/27
 **/
@Tag(name = "数据处理", description = "数据处理")
@RefreshScope
@Slf4j
@RestController
@RequestMapping("/api/asset/data")
public class AssetNoHandlerController {
    @Autowired
    private ITblAssetService iTblAssetService;
    @Autowired
    private ITblAssetExtService iTblAssetExtService;
    @Autowired
    private ITblAssetNoService iTblAssetNoService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ITblAssetCardService iTblAssetCardService;

    @GetMapping("/card")
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> handleCardData(){
        // 1. 查询所有的卡片
        List<TblAssetCard> assetCards = iTblAssetCardService.lambdaQuery()
                .eq(TblAssetCard::getAssetNoId,0L)
                .eq(TblAssetCard::getDestoryState, AssetCardDestoryStatenum.NORMAL.code())
                .orderByAsc(TblAssetCard::getAssetId)
                .list();
        if (!CollectionUtils.isEmpty(assetCards)){
            BoundHashOperations<String, String, Long> boundHashOpsFak = stringRedisTemplate.boundHashOps("nft:seqno:fake");
            BoundHashOperations<String, String, Long> boundHashOpsAct = stringRedisTemplate.boundHashOps("nft:seqno:act");
            for (TblAssetCard assetCard : assetCards) {
                TblAsset tblAsset = iTblAssetService.getById(assetCard.getAssetId());
                if (tblAsset.getRootAssetId() == null || tblAsset.getRootAssetId() == 0L){
                    log.warn("handleCardData rootAssetId is null assetId:{}", tblAsset.getId());
                    continue;
                }
                boundHashOpsAct.increment(tblAsset.getRootAssetId()+"", 1);
                Long incrementFak = boundHashOpsFak.increment(tblAsset.getRootAssetId()+"", 1);
                Long now = System.currentTimeMillis();
                long assetNoId = IdUtil.getSnowflakeNextId();
                TblAssetNo tblAssetNo = TblAssetNo.builder()
                        .id(assetNoId)
                        .rootAssetId(tblAsset.getRootAssetId())
                        .assetNo(incrementFak + "")
                        .assetId(assetCard.getAssetId())
                        .appUserId(assetCard.getOwnerId())
                        .assetType(0)
                        .source("purchase")
                        .noStatus(0)
                        .createTime(now)
                        .updateTime(now)
                        .receiveTime(now)
                        .build();
                iTblAssetNoService.save(tblAssetNo);

                //更新card
                assetCard.setAssetNoId(assetNoId);
                assetCard.setAssetNo(incrementFak+"");
                assetCard.setUpdateTime(LocalDateTime.now());
                iTblAssetCardService.updateById(assetCard);
            }

        }
        return ApiResult.ok();
    }


    @GetMapping("/rose")
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> handleRoseData(@RequestParam(required = false) Long assetId) {
        if (assetId != null) {
            innerHandleRoseData(assetId);
        } else {
            int curPage = 1;
            Page<TblAsset> page = iTblAssetService.lambdaQuery()
                    .eq(TblAsset::getSecondType, SecondEnum.ROSE.getCode())
                    .orderByAsc(TblAsset::getId)
                    .page(new Page<TblAsset>(curPage, 10));
            while (page.getRecords().size() > 0) {
                page.getRecords().forEach(tblAsset -> {
                    innerHandleRoseData(tblAsset.getId());
                });
                curPage++;
                page = iTblAssetService.lambdaQuery()
                        .eq(TblAsset::getSecondType, SecondEnum.ROSE.getCode())
                        .orderByAsc(TblAsset::getId)
                        .page(new Page<TblAsset>(curPage, 10));
            }
        }
        return ApiResult.ok();
    }

    private void innerHandleRoseData(Long assetId) {
        log.info("innerHandleRoseData assetId:{}", assetId);
        TblAsset asset = iTblAssetService.getById(assetId);
        if (asset == null || StringUtils.isBlank(asset.getGoodsId())
                || asset.getRootAssetId() == null
                || asset.getRootAssetId() == 0) {
            log.warn("asset is null or goodsId is null assetId:{}", assetId);
            return;
        }
        List<TblAsset> childrenAsset = iTblAssetService.lambdaQuery()
                .eq(TblAsset::getParentId, asset.getGoodsId()).list();
        Map<Long, TblAsset> assetMap =
                childrenAsset.stream().collect(Collectors.toMap(TblAsset::getId, tblAsset -> tblAsset));

        List<TblAssetExt> assetExts = iTblAssetExtService.infoWithAssetIds(childrenAsset.stream().map(TblAsset::getId).toList());
        for (TblAssetExt assetExt : assetExts) {
            Long id = assetExt.getAssetId();
            Long rootAssetId = assetMap.get(id).getRootAssetId();
            if (rootAssetId == null || rootAssetId == 0) {
                log.warn("rootAssetId is null assetId:{}", id);
                continue;
            }

            Long seqNo = assetExt.getSeqNo();
            //判断是否已经生成过
            Long count = iTblAssetNoService.lambdaQuery()
                    .eq(TblAssetNo::getRootAssetId,rootAssetId)
//                    .eq(TblAssetNo::getAssetId,id)
                    .eq(TblAssetNo::getAssetNo,seqNo + "")
//                    .eq(TblAssetNo::getAppUserId,Long.valueOf(assetMap.get(id).getOwnerId()))
                    .count();
            if (count > 0){
                log.warn("assetNo is exists assetId:{},seqNo:{}", id, seqNo);
                continue;
            }

            Long now = System.currentTimeMillis();
            TblAssetNo tblAssetNo = TblAssetNo.builder()
                    .id(IdUtil.getSnowflakeNextId())
                    .rootAssetId(rootAssetId)
                    .assetNo(seqNo + "")
                    .assetId(id)
                    .appUserId(Long.valueOf(assetMap.get(id).getOwnerId()))
                    .assetType(0)
                    .source("purchase")
                    .noStatus(0)
                    .createTime(now)
                    .updateTime(now)
                    .receiveTime(now)
                    .build();

            iTblAssetNoService.save(tblAssetNo);
            log.info("save tblAssetNo:{}", JSONUtil.toJsonStr(tblAssetNo));
            //插缓存
            BoundHashOperations<String, String, String> boundHashOpsFak = stringRedisTemplate.boundHashOps("nft:seqno:fake");
            BoundHashOperations<String, String, String> boundHashOpsAct = stringRedisTemplate.boundHashOps("nft:seqno:act");
            String existsVal = boundHashOpsFak.get(String.valueOf(rootAssetId));
            if (existsVal == null ||  Long.valueOf( existsVal) < seqNo) {
                boundHashOpsFak.put(String.valueOf(rootAssetId), seqNo+"");
            }
            String actVal = boundHashOpsAct.get(String.valueOf(rootAssetId));
            if (actVal == null || Long.valueOf(actVal) < seqNo) {
                boundHashOpsAct.put(String.valueOf(rootAssetId), seqNo+"");
            }
        }

    }
}
